package com.giraffe.mqtt.service;

import com.giraffe.mqtt.bean.MqttChannel;
import com.giraffe.mqtt.cache.CacheMap;
import com.giraffe.mqtt.utils.TopicUtils;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import io.netty.channel.Channel;
import io.netty.util.AttributeKey;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.util.Collection;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @Author ldx
 * @Date 2024/01/15 15:06
 **/
@Slf4j
@Data
@Service
public class ChannelService {

    private static ConcurrentHashMap<String, MqttChannel> mqttChannels = new ConcurrentHashMap<>();
    protected static CacheMap<String, MqttChannel> cacheMap = new CacheMap<>();
    protected static Cache<String, Collection<MqttChannel>> mqttChannelCache = CacheBuilder.newBuilder().maximumSize(100).build();
    private AttributeKey<Boolean> LOGIN = AttributeKey.valueOf("login");

    private AttributeKey<String> DEVICE_ID = AttributeKey.valueOf("deviceId");

    public void setChannelDeviceId(String deviceId, Channel channel) {
        channel.attr(LOGIN).set(true);
        channel.attr(DEVICE_ID).set(deviceId);
    }

    public MqttChannel getMqttChannel(String deviceId) {
        return mqttChannels.get(deviceId);
    }

    public void saveMqttChannel(String deviceId, MqttChannel mqttChannel) {
        if (mqttChannels.containsKey(deviceId)) {
            mqttChannels.remove(deviceId);
        }
        mqttChannels.put(deviceId, mqttChannel);
    }

    public void removeMqttChannel(String deviceId) {
        mqttChannels.remove(deviceId);
    }

    /**
     * 获取channelId
     */
    public String getDeviceId(Channel channel) {
        return Optional.ofNullable(channel).map(channel1 -> channel1.attr(DEVICE_ID).get()).orElse(null);
    }

    public MqttChannel getMqttChannelByChannel(Channel channel) {
        return Optional.ofNullable(channel).map(channel1 -> mqttChannels.get(channel1.attr(DEVICE_ID).get())).orElse(null);
    }

    public Collection<MqttChannel> getChannels(String topic, TopicFilter topicFilter) {
        try {
            return mqttChannelCache.get(topic, () -> topicFilter.filter(topic));
        } catch (Exception e) {
            log.info(String.format("guava cache key topic【%s】 channel   value== null ", topic));
        }
        return null;
    }


    @FunctionalInterface
    interface TopicFilter {
        Collection<MqttChannel> filter(String topic);
    }

    public boolean deleteChannel(String topic, MqttChannel mqttChannel) {

        return Optional.ofNullable(topic).map(s -> {
            mqttChannelCache.invalidate(s);
            return cacheMap.delete(TopicUtils.getTopic(s), mqttChannel);
        }).orElse(false);
    }

    public boolean addChannel(String topic, MqttChannel mqttChannel) {
        return Optional.ofNullable(topic).map(s -> {
            mqttChannelCache.invalidate(s);
            return cacheMap.putData(TopicUtils.getTopic(s), mqttChannel);
        }).orElse(false);
    }

    public List<MqttChannel> getCashMapData(String topic){
        return cacheMap.getData(TopicUtils.getTopic(topic));
    }

    public void putCashMapData(String topic, MqttChannel mqttChannel){
        cacheMap.putData(TopicUtils.getTopic(topic), mqttChannel);
    }
}
